#include "instructions/references/invoke_virtual.hpp"
#include "rtda/frame.h"
#include "rtda/heap/cp_methodref.h"
#include <iostream>
#include <stdexcept>

namespace jvm {
namespace instructions {

void InvokeVirtual::Execute(Frame& frame) {
    auto cp = frame.GetMethod()->GetClass()->GetConstantPool();
    auto methodRef = std::dynamic_pointer_cast<MethodRef>(cp->GetConstant(index_));
    
    if (methodRef->GetName() == "println") {
        auto stack = frame.GetOperandStack();
        auto descriptor = methodRef->GetDescriptor();
        
        if (descriptor == "(Z)V") {
            std::cout << (stack->PopInt() != 0) << std::endl;
        } else if (descriptor == "(C)V") {
            std::cout << static_cast<char>(stack->PopInt()) << std::endl;
        } else if (descriptor == "(I)V" || descriptor == "(B)V" || descriptor == "(S)V") {
            std::cout << stack->PopInt() << std::endl;
        } else if (descriptor == "(F)V") {
            std::cout << stack->PopFloat() << std::endl;
        } else if (descriptor == "(J)V") {
            std::cout << stack->PopLong() << std::endl;
        } else if (descriptor == "(D)V") {
            std::cout << stack->PopDouble() << std::endl;
        } else {
            throw std::runtime_error("println: " + descriptor);
        }
        stack->PopRef();
    }
}

} // namespace instructions
} // namespace jvm